﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace DawnOfConquest
{

    class TacticalBattle
    {
        #region fields
        //determines the input for each player and what options to draw on menu
        public enum ControlState
        {
            selectUnit, chooseOption, move, selectTarget, endGame, endTurn
        }
        private Avatar p1Avatar;
        private Avatar p2Avatar;
        private List<Piece> player1Army;
        private List<Piece> player2Army;

        //boolean controls
        private Boolean isPlayer1Turn;
        public Boolean battleOver;
        private Boolean gridOn;

        private TacMap map;

        //controls
        private MouseState oldMouse;
        private MouseState mouseState;
        public Boolean mouseVisible;
        private KeyboardState keyboardState;
        private KeyboardState oldKeyboardState;

        //unit control
        private Piece selectedUnit;
        private Tile selectedTile;
        private Tile scrolledOver;
        private List<Tile> selectionTiles;
        private Ability currentAbility;

        //menu info
        private String status;
        private String terrainInfo;
        private String unitInfo;
        private Texture2D confirmation;
        private Texture2D winBox;

        //interface
        private Texture2D background;
        private Texture2D moveBox;
        private Texture2D targetBox;
        private Texture2D selectedBox;
        private Texture2D horizontal;
        private Texture2D vertical;

        //fonts
        private SpriteFont statusFont;
        private SpriteFont playerFont;
        private SpriteFont infoFont;

        public ControlState controlState;                //get and set the control state
        #endregion

        #region constructor/load
        public TacticalBattle(List<Piece> player1Army, List<Piece> player2Army, TacMap map, ContentManager content)
        {
            //p1Avatar = player1;
            //p2Avatar = player2;

            this.player1Army = player1Army;
            this.player2Army = player2Army;

            isPlayer1Turn = true;
            this.map = map;
            battleOver = false;
            gridOn = false;

            mouseVisible = true;
            controlState = ControlState.selectUnit;

            selectedUnit = null;
            status = "Combat begins";
            selectionTiles = new List<Tile>();
            unitInfo = "";
            //load interface items                  TODO
            confirmation = content.Load<Texture2D>("confirmationPopup");
            background = content.Load<Texture2D>("TerrainSprites/battle");
            statusFont = content.Load<SpriteFont>("Arial");
            playerFont = content.Load<SpriteFont>("playerFont");
            infoFont = content.Load<SpriteFont>("infoFont");
            moveBox = content.Load<Texture2D>("TerrainSprites/move");
            targetBox = content.Load<Texture2D>("TerrainSprites/target");
            selectedBox = content.Load<Texture2D>("TerrainSprites/selected");
            horizontal = content.Load<Texture2D>("TerrainSprites/horizontal");
            vertical = content.Load<Texture2D>("TerrainSprites/vertical");
            winBox = content.Load<Texture2D>("Menu/Win message");
            //set units to starting positions
            startingPositions();
        }
        #endregion

        #region draw
        public void draw(SpriteBatch spriteBatch, ContentManager content)           //draws the map and then each tile on the map and then the menu
        {
            //background
            spriteBatch.Draw(background, new Vector2(0,0), Color.White);
            //grid
            if(gridOn)
                for (int i = 0; i < 30; i++)
                {
                    spriteBatch.Draw(vertical, new Vector2(i*30, 0), Color.White);
                    spriteBatch.Draw(horizontal, new Vector2(0, i * 30), Color.White);
                 }

            map.draw(spriteBatch, content);

            //menu - depends on state           TODO
            ////TODO find unspent unit
            //draw scroll over unit
            spriteBatch.DrawString(statusFont, status, new Vector2(10, 906), Color.White);  //draw status

            if (isPlayer1Turn)
                spriteBatch.DrawString(playerFont, "PLAYER 1", new Vector2(926, 20), Color.Red);
            else
                spriteBatch.DrawString(playerFont, "PLAYER 2", new Vector2(926, 20), Color.Blue);

            if (controlState == ControlState.selectUnit && (scrolledOver != null))
            {
                //display terrain of scolled over 
                terrainInfo = "Terrain: " + scrolledOver.getTerrain();
                spriteBatch.DrawString(infoFont, terrainInfo, new Vector2(921, 100), Color.White);
                //display unit info of scrolled over
                Piece display = scrolledOver.getResident();
                if (display != null)
                {
                    updateInfo(scrolledOver);
                    spriteBatch.DrawString(infoFont, unitInfo, new Vector2(921, 125), Color.White);  
                }
            }
            else if (controlState == ControlState.chooseOption)
            {
                spriteBatch.Draw(selectedBox, new Vector2((selectedTile.getXCoord() * 30) - 1, (selectedTile.getYCoord() * 30) - 1), Color.White);
                //draw selected unit's info
                updateInfo(selectedTile);
                spriteBatch.DrawString(infoFont, unitInfo, new Vector2(921, 125), Color.White); 
                //draw options
                unitInfo = "    OPTIONS";
                if(!selectedUnit.hasPieceMoved())
                unitInfo += "\nMove (W)";
                if (!selectedUnit.hasPieceAttacked())
                {
                    unitInfo += "\nAttack(A)";
                }
                unitInfo += "\nEnd unit's turn (T)";
                unitInfo += "\nGo back (Space)";
                spriteBatch.DrawString(statusFont, unitInfo, new Vector2(921, 500), Color.Aquamarine);  
                //display options with (-key-) next to each one TODO

            }
            else if (controlState == ControlState.move)                                //if state= move draw green on all canMoveTo spaces
            {
                spriteBatch.Draw(selectedBox, new Vector2((selectedTile.getXCoord() * 30) - 1, (selectedTile.getYCoord() * 30) - 1), Color.White);
                if (scrolledOver != null)
                {
                    terrainInfo = "Terrain: " + scrolledOver.getTerrain();
                    spriteBatch.DrawString(infoFont, terrainInfo, new Vector2(921, 100), Color.White);
                    if (!scrolledOver.isEmpty())
                    {
                        updateInfo(scrolledOver);
                        spriteBatch.DrawString(infoFont, unitInfo, new Vector2(921, 125), Color.White);
                    }
                }
                spriteBatch.DrawString(statusFont, "Select space to \nmove to\n\n Cancel(Space)", new Vector2(921, 500), Color.PaleGreen); 
                //draw info On scrolled Over unit

                //draw green box on valid mvoes
                foreach(Tile t in selectionTiles)
                    spriteBatch.Draw(moveBox, new Vector2((t.getXCoord() * 30) - 1, (t.getYCoord() * 30) - 1), Color.White);
            }
            else if (controlState == ControlState.selectTarget)                         // if state=target draw red on possible targets
            {
                spriteBatch.Draw(selectedBox, new Vector2((selectedTile.getXCoord() * 30) - 1, (selectedTile.getYCoord() * 30) - 1), Color.White);
                //display terrain of scolled over 
                if (scrolledOver != null)
                {
                    terrainInfo = "Terrain: " + scrolledOver.getTerrain();
                    spriteBatch.DrawString(infoFont, terrainInfo, new Vector2(921, 100), Color.White);
                    //display unit info of scrolled over
                    if (!scrolledOver.isEmpty())
                    {
                        updateInfo(scrolledOver);
                        spriteBatch.DrawString(infoFont, unitInfo, new Vector2(921, 125), Color.White);
                    }
                }
                spriteBatch.DrawString(statusFont, "Select target\n\n Cancel(Space)", new Vector2(921, 500), Color.Crimson); 
                //draw targetBox on all tiles in map.getTargets
                foreach (Tile t in selectionTiles)
                    spriteBatch.Draw(targetBox, new Vector2((t.getXCoord() * 30) - 1, (t.getYCoord() * 30) - 1), Color.White);
            }
            else if (controlState == ControlState.endTurn)
            {
                spriteBatch.Draw(confirmation, new Vector2(300, 300), Color.White);
            }
            else if (controlState == ControlState.endGame)
            {
                spriteBatch.Draw(winBox, new Vector2(250, 300), Color.White);
                spriteBatch.DrawString(playerFont, status, new Vector2(350, 370), Color.Black);
            }
        }
        #endregion

        #region update
        public void update()                    //gathers input, updates positions, and handles combat
        {
            //update inputs
            oldMouse = mouseState;
            mouseState = Mouse.GetState();
            oldKeyboardState = keyboardState;
            keyboardState = Keyboard.GetState();

            Rectangle endTurn = new Rectangle(918, 818, 268, 69);
            Rectangle toggleGrid = new Rectangle(1076, 70, 115, 20);
            Rectangle mouse = new Rectangle(mouseState.X, mouseState.Y, 1, 1);
            //TODO find unspent unit

            //click toggle grid button
            if (mouse.Intersects(toggleGrid) && mouseState.LeftButton == ButtonState.Pressed && oldMouse.LeftButton != ButtonState.Pressed)
                gridOn = !gridOn;

            if (controlState == ControlState.selectUnit)
            {
                //change scroll-over display based on mouse coordinates
                scrolledOver = mouseOverTile();
                //if click and scrolled over friendly unit set unit to selected and change state to choose option
                if (mouseState.LeftButton == ButtonState.Pressed)
                {
                    if (mouse.Intersects(endTurn) && oldMouse.LeftButton != ButtonState.Pressed)
                    {
                        //if end turn is clicked then refresh armies and switch players
                        controlState = ControlState.endTurn;
                    }
                    else
                    {
                        if (mouseState.X < 900 && mouseState.Y < 900 && scrolledOver != null && !scrolledOver.isEmpty())
                        {
                            if((scrolledOver.getResident().getFaction().Equals("RED") && isPlayer1Turn) || (scrolledOver.getResident().getFaction().Equals("BLUE") && !isPlayer1Turn))
                            {
                                if (!scrolledOver.getResident().hasPieceAttacked())
                                {
                                    selectedTile = scrolledOver;
                                    selectedUnit = scrolledOver.getResident();

                                    selectionTiles = map.getValidMoves();
                                    controlState = ControlState.chooseOption;
                                    //hide mouse
                                    mouseVisible = false;
                                }
                                else
                                    status = "Unit is spent for this turn";
                            }
                        }
                    }
                }
                if (keyboardState.IsKeyDown(Keys.K))            //test win screen
                {
                    status = "Nobody wins! YAY!";
                    controlState = ControlState.endGame;
                }

            }
            else if (controlState == ControlState.chooseOption)
            {
                //if keyboardState has a button pressed coressponding to the options then change state and show mouse TODO
                if (keyboardState.IsKeyDown(Keys.W) && !selectedUnit.hasPieceMoved())            //move
                {
                    mouseVisible = true;
                    selectionTiles = map.findValidMoves(selectedUnit);
                    controlState = ControlState.move;
                }
                else if (keyboardState.IsKeyDown(Keys.A) && !selectedUnit.hasPieceAttacked())       //attack
                {
                    mouseVisible = true;
                    currentAbility = new Attack(selectedUnit);
                    selectionTiles = map.checkRange(selectedTile, currentAbility, currentAbility.getRange(), selectedUnit);
                    //if no targets in range status "says so" and don't change state
                    controlState = ControlState.selectTarget;
                }
                else if (keyboardState.IsKeyDown(Keys.T))       //end turn
                {
                    //selectedUnit.move();
                    selectedUnit.attack();                      //TODO
                    mouseVisible = true;
                    controlState = ControlState.selectUnit;
                }
                else if (keyboardState.IsKeyDown(Keys.Space) && !oldKeyboardState.IsKeyDown(Keys.Space))
                {
                    mouseVisible = true;
                    controlState = ControlState.selectUnit;
                }
                //space = cancel, go back to selectUnit
            }
            else if (controlState == ControlState.move)
            {
                //change scroll-over display based on mouse coordinates
                scrolledOver = mouseOverTile();
                //if click and mouse XY corresponds to valid tile then move unit and return to chooseoption TODO
                if (selectionTiles.Contains(mouseOverTile()) && mouseState.LeftButton == ButtonState.Pressed)
                {
                    map.movePiece(selectedTile, scrolledOver, selectedUnit);
                    selectedTile = scrolledOver;
                    selectedUnit.move();
                    status = selectedUnit.getName() + " has moved.";
                    mouseVisible = false;
                    controlState = ControlState.chooseOption;
                }
                else if (keyboardState.IsKeyDown(Keys.Space) && !oldKeyboardState.IsKeyDown(Keys.Space))
                {
                    mouseVisible = false;
                    controlState = ControlState.chooseOption;
                }
                //space = cancel, go back to chooseOption
            }
            else if (controlState == ControlState.selectTarget)
            {
                //change scroll-over display based on mouse coordinates
                scrolledOver = mouseOverTile();
                
                //if click and tile is in target list than initiate combat between selected unit and target, show mouse, return to select unit TODO
                if (mouseState.LeftButton == ButtonState.Pressed)
                {
                    //if scrolled over tile is within targetTiles then initiate combat
                    if(selectionTiles.Contains(scrolledOver))
                    {
                        //change status to combat result string
                        status = currentAbility.execute(selectedUnit, scrolledOver.getResident());
                        selectedUnit.attack();
                        //remove dead units
                        if (selectedUnit.getHealth() < 1)
                            selectedTile.removePiece();
                        if (scrolledOver.getResident().getHealth() < 1)
                            scrolledOver.removePiece();
                        controlState = ControlState.selectUnit;
                        //status = "attack";
                    }
                }
                else if (keyboardState.IsKeyDown(Keys.Space) && !oldKeyboardState.IsKeyDown(Keys.Space))
                {
                    currentAbility = null;
                    mouseVisible = false;
                    controlState = ControlState.chooseOption;
                }
                //space = cancel, go back to chooseOption
            }
            else if (controlState == ControlState.endTurn)
            {
                if (keyboardState.IsKeyDown(Keys.Y))
                {
                    refreshArmy();
                    isPlayer1Turn = !isPlayer1Turn;
                    //refreshArmy();
                    status = "Turn ended, next player's turn begins";
                    controlState = ControlState.selectUnit;
                }
                else if (keyboardState.IsKeyDown(Keys.Space))
                {
                    controlState = ControlState.selectUnit;
                }
            }
            else if(controlState == ControlState.endGame)
            {

                //continue
                if (keyboardState.IsKeyDown(Keys.Space))
                {
                   endBattle();
                }
            }

            if (isArmyDead(player1Army))
            {
                status = "Blue Player 2 Wins!";
            }
            else if (isArmyDead(player2Army))
            {
                status = "Red Player 1 Wins!";
            }
        }
        #endregion

        #region helper methods
        //method that returns the tile that a mouse is scrolled over based on mouseXY coordinates (divide by size of tile to get it)
        private Tile mouseOverTile()
        {
            int x = mouseState.X/30;
            int y = mouseState.Y/30;

            if (x < 30 && y < 30 && x >= 0 && y >= 0)
            {
                return map.getTile(x , y);
            }
            else
                return null;
        }

            //method returning a list of all tiles that the selected unit can move to 

            //method returning a list of all units within attack range of selected unit

            //method that goes through array of each army and sets hasMoved and hasAttacked to false
        private void refreshArmy()
        {
            if(isPlayer1Turn)
                foreach (Piece i in player1Army)
                    { i.resetUnit(); }
            else
                foreach (Piece i in player2Army)
                { i.resetUnit(); }
        }

        private Boolean isArmyDead(List<Piece> army)
        {
            foreach (Piece i in player1Army)
                if (i.getHealth() > 0)
                    return false;
            return true;
        }

        private void endBattle()
        {
            mouseVisible = true;
            battleOver = true;
        }

        public TacMap getMap()
        { return map; }

        public void startingPositions()
        {
            /*map.getTile(5, 5).enterPiece(player1Army[0]);
            map.getTile(3, 3).enterPiece(player1Army[0]);
            map.getTile(0, 10).enterPiece(player1Army[0]);
            map.getTile(10, 0).enterPiece(player1Army[0]);

            map.getTile(25, 25).enterPiece(player2Army[0]);
            map.getTile(27, 27).enterPiece(player2Army[0]);
            map.getTile(15, 15).enterPiece(player2Army[0]);
            map.getTile(15, 16).enterPiece(player2Army[0]);*/
            int y = 0;
            int x = 0;
            foreach (Piece p in player1Army)
            {
                map.getTile(x, y).enterPiece(p);
                p.setPosition(x, y);
                x++;
                //p.setPosition(x, y);
                if(x>4)
                {
                    x = 0;
                    y++;
                }
            }
            y = 29;
            x = 25;
            foreach (Piece p in player2Army)
            {
                map.getTile(x, y).enterPiece(p);
                p.setPosition(x, y);
                x++;
                if (x > 29)
                {
                    x = 25;
                    y--;
                }
            }
        }

        public void updateInfo(Tile t)
        {
            if (t.getResident() != null)
            {
                Piece display = t.getResident();
                unitInfo = "    UNIT \n Name : " + display.getName();
                unitInfo += "\nLevel: " + display.getLevel();
                unitInfo += "\nAttack: " + display.getAttack();
                unitInfo += "\nDefense: " + display.getDefense();
                unitInfo += "\nRange: " + display.getRange();
                unitInfo += "\nHealth: " + display.getHealth() + "/" + (5 * display.getStamina());
                unitInfo += "\nAction points: " + display.getAP();
                unitInfo += "\nExp: " + display.getXP() + "/" + display.maxXP();
                unitInfo += "\n";
                unitInfo += "\n";
                if (display.hasPieceAttacked())
                    unitInfo += "\nUnit is spent for \nthis turn";
                else if (display.hasPieceMoved())
                    unitInfo += "\nUnit has moved \nbut can still attack";
                else
                    unitInfo += "\nUnit can still move \nthis turn";
            }
        }
    }
        #endregion
}
